//
//  KooCalendarView.m
//  KooIEDUCalendarDemo
//
//  Created by nowcoder on 2024.
//

#import "KooCalendarView.h"
#import "KooCalendarModel.h"
#import "KooCalendarConfig.h"
#import "KooCalendarCell.h"
#import "KooCalendarHeader.h"
#import "KooCalendarWeekView.h"
#import "KooCalendarFlowLayout.h"
#import <Masonry/Masonry.h>

@interface KooCalendarView () <UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout>

// UI Components
@property (nonatomic, strong) KooCalendarHeader *headerView;
@property (nonatomic, strong) KooCalendarWeekView *weekView;
@property (nonatomic, strong) UICollectionView *collectionView;
@property (nonatomic, strong) KooCalendarFlowLayout *flowLayout;

// Data and State
@property (nonatomic, strong) KooCalendarModel *calendarModel;
@property (nonatomic, strong) NSMutableSet<NSDate *> *mutableSelectedDates;

// Multi-Month Support
@property (nonatomic, strong) NSMutableArray<KooCalendarModel *> *monthModels;
@property (nonatomic, assign) NSInteger currentMonthIndex;
@property (nonatomic, assign) NSInteger totalMonths;

@end

@implementation KooCalendarView

static NSString * const KooCalendarCellIdentifier = @"KooCalendarCell";

#pragma mark - Initialization

- (instancetype)init {
    return [self initWithConfig:[KooCalendarConfig defaultConfig]];
}

- (instancetype)initWithConfig:(KooCalendarConfig *)config {
    return [self initWithConfig:config preSelectedDates:@[]];
}

- (instancetype)initWithPreSelectedDates:(NSArray<NSDate *> *)preSelectedDates {
    return [self initWithConfig:[KooCalendarConfig defaultConfig] preSelectedDates:preSelectedDates];
}

- (instancetype)initWithConfig:(KooCalendarConfig *)config preSelectedDates:(NSArray<NSDate *> *)preSelectedDates {
    self = [super init];
    if (self) {
        self.config = config ?: [KooCalendarConfig defaultConfig];
        self.currentDate = [NSDate date];
        [self setupDataModel];
        [self setupPreSelectedDates:preSelectedDates];
        [self setupUI];
        [self setupConstraints];
        [self finalizeUISetup];
    }
    return self;
}

- (instancetype)initWithFrame:(CGRect)frame {
    self = [super initWithFrame:frame];
    if (self) {
        self.config = [KooCalendarConfig defaultConfig];
        self.currentDate = [NSDate date];
        [self setupDataModel];
        [self setupUI];
        [self setupConstraints];
        [self finalizeUISetup];
    }
    return self;
}

#pragma mark - Data Setup

- (void)setupDataModel {
    self.calendarModel = [[KooCalendarModel alloc] initWithCurrentDate:self.currentDate];
    self.mutableSelectedDates = [[NSMutableSet alloc] init];
    
    // 初始化多月份支持
    [self setupMultiMonthData];
}

- (void)setupMultiMonthData {
    self.totalMonths = 12; // 支持前后各6个月，共12个月
    self.currentMonthIndex = self.totalMonths / 2; // 当前月份在中间位置
    self.monthModels = [[NSMutableArray alloc] initWithCapacity:self.totalMonths];
    
    NSCalendar *calendar = [NSCalendar currentCalendar];
    
    // 生成前后各6个月的数据
    for (NSInteger i = 0; i < self.totalMonths; i++) {
        NSInteger monthOffset = i - self.currentMonthIndex;
        NSDate *monthDate = [calendar dateByAddingUnit:NSCalendarUnitMonth value:monthOffset toDate:self.currentDate options:0];
        KooCalendarModel *monthModel = [[KooCalendarModel alloc] initWithCurrentDate:monthDate];
        [self.monthModels addObject:monthModel];
    }
}

- (void)setupPreSelectedDates:(NSArray<NSDate *> *)preSelectedDates {
    if (!preSelectedDates || preSelectedDates.count == 0) return;
    
    // 在所有月份模型中设置预选日期
    for (KooCalendarModel *monthModel in self.monthModels) {
        [monthModel setPreSelectedDates:preSelectedDates];
    }
    [self.mutableSelectedDates addObjectsFromArray:preSelectedDates];
}

#pragma mark - UI Setup

- (void)setupUI {
    self.backgroundColor = self.config.backgroundColor;
    
    // 使用懒加载的方式添加UI组件，避免重复创建
    [self addSubview:self.headerView];
    [self addSubview:self.weekView];
    
    // 创建UICollectionView
    [self setupCollectionView];
}

- (void)setupCollectionView {
    // 使用懒加载的方式添加CollectionView，避免重复创建
    [self addSubview:self.collectionView];
}

- (void)configureFlowLayout {
    [self.flowLayout updateWithConfig:self.config];
}

- (void)layoutSubviews {
    [super layoutSubviews];
    
    // 视图布局发生变化时，重新配置CollectionView布局以确保对齐
    [self.flowLayout updateWithConfig:self.config];
    [self.collectionView.collectionViewLayout invalidateLayout];
    
    // 确保CollectionView滚动到当前月份
    [self scrollToCurrentMonth:NO];
}

- (void)scrollToCurrentMonth:(BOOL)animated {
    if (self.currentMonthIndex >= 0 && self.currentMonthIndex < self.totalMonths) {
        CGFloat pageWidth = CGRectGetWidth(self.collectionView.bounds);
        CGFloat offsetX = self.currentMonthIndex * pageWidth;
        [self.collectionView setContentOffset:CGPointMake(offsetX, 0) animated:animated];
    }
}

- (void)setupConstraints {
    // 头部视图约束
    [self.weekView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.left.right.equalTo(self);
        make.height.equalTo(@(self.config.weekViewHeight));
    }];
    
    // 星期视图约束
    [self.headerView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.equalTo(self.weekView.mas_bottom);
        make.left.right.equalTo(self);
        make.height.equalTo(@(self.config.headerHeight));
    }];
    
    // CollectionView约束
    [self.collectionView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.equalTo(self.headerView.mas_bottom);
        make.left.right.bottom.equalTo(self);
    }];
}

- (void)finalizeUISetup {
    // 确保headerView的titleLabel正确显示当前日期
    [self.headerView updateCurrentDate:self.currentDate];
}

#pragma mark - Public Methods

- (void)reloadCalendar {
    [self.collectionView reloadData];
    [self.headerView updateCurrentDate:self.currentDate];
    [self scrollToCurrentMonth:NO];
}

- (void)switchToMonth:(NSDate *)date {
    if (!date) return;
    
    // 查找目标月份在monthModels中的索引
    NSCalendar *calendar = [NSCalendar currentCalendar];
    NSInteger targetMonthIndex = -1;
    
    for (NSInteger i = 0; i < self.monthModels.count; i++) {
        KooCalendarModel *monthModel = self.monthModels[i];
        if ([calendar isDate:date equalToDate:monthModel.currentMonthDate toUnitGranularity:NSCalendarUnitMonth]) {
            targetMonthIndex = i;
            break;
        }
    }
    
    if (targetMonthIndex >= 0) {
        self.currentMonthIndex = targetMonthIndex;
        self.currentDate = date;
        [self.headerView updateCurrentDate:date];
        
        // 滚动到目标月份
        [self scrollToCurrentMonth:YES];
        
        // 通知代理月份切换
        if (self.delegate && [self.delegate respondsToSelector:@selector(calendarView:monthChangedTo:)]) {
            [self.delegate calendarView:self monthChangedTo:date];
        }
    }
}

- (BOOL)selectDate:(NSDate *)date {
    // 检查最大选择数量限制
    if (self.mutableSelectedDates.count >= self.config.maxSelectCount) {
        if (self.delegate && [self.delegate respondsToSelector:@selector(calendarView:reachedMaxSelectCount:)]) {
            [self.delegate calendarView:self reachedMaxSelectCount:self.config.maxSelectCount];
        }
        return NO;
    }
    
    // 检查DataSource是否允许选择
    if (self.dataSource && [self.dataSource respondsToSelector:@selector(calendarView:shouldSelectDate:)]) {
        if (![self.dataSource calendarView:self shouldSelectDate:date]) {
            return NO;
        }
    }
    
    // 在所有月份模型中选择日期
    BOOL success = NO;
    for (KooCalendarModel *monthModel in self.monthModels) {
        if ([monthModel selectDate:date]) {
            success = YES;
        }
    }
    
    if (success) {
        [self.mutableSelectedDates addObject:date];
        [self.collectionView reloadData];
        
        // 添加震动反馈效果
        [self triggerHapticFeedback];
        
        // 通知代理选择状态变化
        [self notifySelectionChanged:date isSelected:YES];
    }
    
    return success;
}

- (void)deselectDate:(NSDate *)date {
    // 在所有月份模型中取消选择日期
    for (KooCalendarModel *monthModel in self.monthModels) {
        [monthModel deselectDate:date];
    }
    [self.mutableSelectedDates removeObject:date];
    [self.collectionView reloadData];
    
    // 添加震动反馈效果
    [self triggerHapticFeedback];
    
    // 通知代理选择状态变化
    [self notifySelectionChanged:date isSelected:NO];
}

- (void)clearSelectedDates {
    NSArray *selectedDates = [self.mutableSelectedDates allObjects];
    
    // 在所有月份模型中清空选择
    for (KooCalendarModel *monthModel in self.monthModels) {
        [monthModel clearSelectedDates];
    }
    [self.mutableSelectedDates removeAllObjects];
    [self.collectionView reloadData];
    
    // 通知代理清空选择
    for (NSDate *date in selectedDates) {
        [self notifySelectionChanged:date isSelected:NO];
    }
}

- (NSDate *)removeLastSelectedDate {
    NSArray *selectedDates = [self.mutableSelectedDates allObjects];
    if (selectedDates.count == 0) {
        return nil;
    }
    
    // 对日期进行排序，获取最后一个（最新的）日期
    NSArray *sortedDates = [selectedDates sortedArrayUsingComparator:^NSComparisonResult(NSDate *date1, NSDate *date2) {
        return [date1 compare:date2];
    }];
    
    NSDate *lastDate = sortedDates.lastObject;
    
    // 取消选中最后一个日期
    [self deselectDate:lastDate];
    
    return lastDate;
}

- (BOOL)isDateSelected:(NSDate *)date {
    return [self.mutableSelectedDates containsObject:date];
}

- (void)setSelectedDates:(NSArray<NSDate *> * _Nullable)dates animated:(BOOL)animated {
    // 保存原有选中的日期
    NSArray *previousSelectedDates = [self.mutableSelectedDates allObjects];
    
    // 清空当前选中状态
    for (KooCalendarModel *monthModel in self.monthModels) {
        [monthModel clearSelectedDates];
    }
    [self.mutableSelectedDates removeAllObjects];
    
    // 设置新的选中日期
    if (dates && dates.count > 0) {
        // 过滤有效的日期并检查数量限制
        NSMutableArray *validDates = [[NSMutableArray alloc] init];
        for (NSDate *date in dates) {
            if (validDates.count >= self.config.maxSelectCount) {
                // 达到最大选择数量限制
                if (self.delegate && [self.delegate respondsToSelector:@selector(calendarView:reachedMaxSelectCount:)]) {
                    [self.delegate calendarView:self reachedMaxSelectCount:self.config.maxSelectCount];
                }
                break;
            }
            
            // 检查DataSource是否允许选择
            BOOL canSelect = YES;
            if (self.dataSource && [self.dataSource respondsToSelector:@selector(calendarView:shouldSelectDate:)]) {
                canSelect = [self.dataSource calendarView:self shouldSelectDate:date];
            }
            
            if (canSelect) {
                [validDates addObject:date];
            }
        }
        
        // 在所有月份模型中设置选中日期
        for (NSDate *date in validDates) {
            for (KooCalendarModel *monthModel in self.monthModels) {
                [monthModel selectDate:date];
            }
            [self.mutableSelectedDates addObject:date];
        }
    }
    
    // 更新UI
    if (animated) {
        [UIView animateWithDuration:0.3 delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
            [self.collectionView reloadData];
        } completion:nil];
    } else {
        [self.collectionView reloadData];
    }
    
    // 通知代理日期选择状态变化
    NSSet *previousSet = [NSSet setWithArray:previousSelectedDates];
    NSSet *currentSet = [NSSet setWithArray:[self.mutableSelectedDates allObjects]];
    
    // 通知取消选中的日期
    for (NSDate *date in previousSelectedDates) {
        if (![currentSet containsObject:date]) {
            [self notifySelectionChanged:date isSelected:NO];
        }
    }
    
    // 通知新选中的日期
    for (NSDate *date in [self.mutableSelectedDates allObjects]) {
        if (![previousSet containsObject:date]) {
            [self notifySelectionChanged:date isSelected:YES];
        }
    }
}

#pragma mark - Private Helper Methods

- (void)triggerHapticFeedback {
    // 触觉反馈，支持iOS 10+
    if (@available(iOS 10.0, *)) {
        UIImpactFeedbackGenerator *impactFeedback = [[UIImpactFeedbackGenerator alloc] initWithStyle:UIImpactFeedbackStyleLight];
        [impactFeedback prepare];
        [impactFeedback impactOccurred];
    }
}

- (void)triggerUnselectableHapticFeedback {
    // 不可选择日期的触觉反馈，使用错误通知类型
    if (@available(iOS 10.0, *)) {
        UINotificationFeedbackGenerator *notificationFeedback = [[UINotificationFeedbackGenerator alloc] init];
        [notificationFeedback prepare];
        [notificationFeedback notificationOccurred:UINotificationFeedbackTypeError];
    }
}

- (void)notifySelectionChanged:(NSDate *)date isSelected:(BOOL)isSelected {
    if (self.delegate && [self.delegate respondsToSelector:@selector(calendarView:selectedDates:changedDate:isSelected:)]) {
        NSArray *selectedDates = [self.mutableSelectedDates allObjects];
        [self.delegate calendarView:self selectedDates:selectedDates changedDate:date isSelected:isSelected];
    }
}
#pragma mark - UICollectionViewDataSource

- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
    return self.totalMonths;
}

- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
    if (section < self.monthModels.count) {
        KooCalendarModel *monthModel = self.monthModels[section];
        return monthModel.cellModels.count;
    }
    return 0;
}

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
    KooCalendarCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:KooCalendarCellIdentifier forIndexPath:indexPath];
    
    if (indexPath.section < self.monthModels.count) {
        KooCalendarModel *monthModel = self.monthModels[indexPath.section];
        if (indexPath.item < monthModel.cellModels.count) {
            KooCalendarCellModel *cellModel = monthModel.cellModels[indexPath.item];
            
            // 检查是否有自定义显示文本
            if (self.dataSource && [self.dataSource respondsToSelector:@selector(calendarView:displayTextForDate:)]) {
                NSString *customText = [self.dataSource calendarView:self displayTextForDate:cellModel.date];
                if (customText) {
                    cellModel.displayText = customText;
                }
            }
            
            [cell configureCellWithModel:cellModel config:self.config];
        }
    }
    
    return cell;
}

#pragma mark - UICollectionViewDelegate

- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
    if (indexPath.section >= self.monthModels.count) return;
    
    KooCalendarModel *monthModel = self.monthModels[indexPath.section];
    if (indexPath.item >= monthModel.cellModels.count) return;
    
    KooCalendarCellModel *cellModel = monthModel.cellModels[indexPath.item];
    
    // 检查日期是否可选择
    if (!cellModel.isSelectable) {
        // 触发不可选择日期的震动反馈
        [self triggerUnselectableHapticFeedback];
        return;
    }
    
    NSDate *selectedDate = cellModel.date;
    
    if ([self.mutableSelectedDates containsObject:selectedDate]) {
        // 取消选择
        [self deselectDate:selectedDate];
    } else {
        // 选择日期
        [self selectDate:selectedDate];
    }
}

#pragma mark - UICollectionViewDelegateFlowLayout

- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
    if ([self.flowLayout respondsToSelector:@selector(calculatedCellSize)]) {
        return [self.flowLayout calculatedCellSize];
    }
    return self.config.cellSize;
}

- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {
    return UIEdgeInsetsZero;
}

- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section {
    return self.config.cellSpacing.height;
}

- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section {
    return self.config.cellSpacing.width;
}

- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section {
    return CGSizeZero;
}

- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout referenceSizeForFooterInSection:(NSInteger)section {
    return CGSizeZero;
}

#pragma mark - UIScrollViewDelegate

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
    [self updateCurrentMonthFromScrollView];
}

- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
    if (!decelerate) {
        [self updateCurrentMonthFromScrollView];
    }
}

- (void)updateCurrentMonthFromScrollView {
    CGFloat pageWidth = CGRectGetWidth(self.collectionView.bounds);
    CGFloat currentPage = self.collectionView.contentOffset.x / pageWidth;
    NSInteger newMonthIndex = (NSInteger)round(currentPage);
    
    if (newMonthIndex >= 0 && newMonthIndex < self.monthModels.count && newMonthIndex != self.currentMonthIndex) {
        self.currentMonthIndex = newMonthIndex;
        KooCalendarModel *currentMonthModel = self.monthModels[self.currentMonthIndex];
        self.currentDate = currentMonthModel.currentMonthDate;
        
        // 更新header显示
        [self.headerView updateCurrentDate:self.currentDate];
        
        // 通知代理月份切换
        if (self.delegate && [self.delegate respondsToSelector:@selector(calendarView:monthChangedTo:)]) {
            [self.delegate calendarView:self monthChangedTo:self.currentDate];
        }
    }
}

#pragma mark - Getters

- (NSArray<NSDate *> *)selectedDates {
    return [self.mutableSelectedDates allObjects];
}

#pragma mark - Setters

- (void)setConfig:(KooCalendarConfig *)config {
    _config = config;
    
    if (self.headerView) {
        [self.headerView updateWithConfig:config];
    }
    if (self.weekView) {
        [self.weekView updateWithConfig:config];
    }
    if (self.flowLayout) {
        [self.flowLayout updateWithConfig:config];
    }
    
    self.backgroundColor = config.backgroundColor;
    [self.collectionView reloadData];
}

#pragma mark - Lazy Loading

- (KooCalendarFlowLayout *)flowLayout {
    if (!_flowLayout) {
        _flowLayout = [[KooCalendarFlowLayout alloc] initWithConfig:self.config];
    }
    return _flowLayout;
}

- (UICollectionView *)collectionView {
    if (!_collectionView) {
        _collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:self.flowLayout];
        _collectionView.backgroundColor = [UIColor clearColor];
        _collectionView.dataSource = self;
        _collectionView.delegate = self;
        _collectionView.showsVerticalScrollIndicator = NO;
        _collectionView.showsHorizontalScrollIndicator = NO;
        _collectionView.pagingEnabled = YES;
        _collectionView.bounces = YES;
        _collectionView.alwaysBounceHorizontal = YES;
        
        // 注册Cell
        [_collectionView registerClass:[KooCalendarCell class] forCellWithReuseIdentifier:KooCalendarCellIdentifier];
    }
    return _collectionView;
}

- (KooCalendarHeader *)headerView {
    if (!_headerView) {
        _headerView = [[KooCalendarHeader alloc] initWithConfig:self.config];
        _headerView.currentDate = self.currentDate;
        
        // 确保titleLabel正确显示当前日期
        [_headerView updateCurrentDate:self.currentDate];
    }
    return _headerView;
}

- (KooCalendarWeekView *)weekView {
    if (!_weekView) {
        _weekView = [[KooCalendarWeekView alloc] initWithConfig:self.config];
    }
    return _weekView;
}

@end 
